/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年9月25日
 */
package com.massyframework.beanskin.runtime.framework.installing;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.massyframework.beanskin.ParseException;
import com.massyframework.beanskin.RequireLibraryDescriptor;
import com.massyframework.beanskin.util.exceptioncollect.ExceptionCollectUtils;
import com.massyframework.beanskin.util.version.VersionRange;

/**
 * 依赖类库Json解析器
 * @author huangkh
 *
 */
public class RequiresJsonParser extends JsonParser{
	
	private static final Logger LOG = LoggerFactory.getLogger(RequiresJsonParser.class);
	
	private static final String GROUPID       = "groupId";
	private static final String MODULEID      = "moduleId";
	private static final String VERSION_RANGE = "version-range";
	private static final String TRANSITIVE    = "transitive";

	/**
	 * 构造方法 
	 */
	public RequiresJsonParser() {
	}
	
	/**
	 * 从{@code url}加载外部的
	 * @param url {@link URL}, 外置requires.json文件
	 * @return {@link List}
	 * @throws IOException 
	 * @throws ProcessingException 
	 * @throws SAXException 
	 */
	public List<RequireLibraryDescriptor> parserRequireLibraries(URL url) 
			throws IOException, SAXException, ProcessingException {
		if (url == null) return Collections.emptyList();
		
		List<RequireLibraryDescriptor> result = new ArrayList<>();
		
		//验证json格式
		URL schemaUrl = this.getSchemaURL();
		JsonNode data = this.loadJsonNode(url);
		this.validateJson(data, schemaUrl);
		
		if (data instanceof ArrayNode) {
			ArrayNode arr = (ArrayNode)data;
			int size = arr.size();
			
			for (int i=0; i<size; i++) {
				JsonNode node = arr.get(i);
				RequireLibraryDescriptor desc =
						this.doParserRequireLibrary(node);
				if (desc != null) {
					result.add(desc);
				}
			}
		}
		
		return result;
	}
	
	protected RequireLibraryDescriptor doParserRequireLibrary(JsonNode node) {
		String groupId = node.get(GROUPID).asText();
		String moduleId = node.get(MODULEID).asText();
		String versionRange = "0.0.0";
		boolean transitive = false;
		
		JsonNode tmp = node.get(VERSION_RANGE);
		if (tmp != null) {
			versionRange = tmp.asText();
		}
		
		tmp = node.get(TRANSITIVE);
		if (tmp != null) {
			transitive = tmp.asBoolean();
		}
		
		try {
			return RequireLibraryDescriptor.newBuilder()
					.groupId(groupId)
					.moduleId(moduleId)
					.versionRange(VersionRange.valueOf(versionRange))
					.transitive(transitive)
					.build();
		}catch(Exception e) {
			String message = "parse require library version range failed, skip.";
			if (LOG.isErrorEnabled()) {
				LOG.error(message, e);
			}
			
			RuntimeException ex = new RuntimeException(message, e);
			ExceptionCollectUtils.addException(ex);
			return null;
		}
	}

	/**
	 * 获取Schema URL
	 * @return {@link URL}
	 */
	protected URL getSchemaURL() {
		URL result = this.getClass().getClassLoader()
				.getResource("com/massyframework/beanskin/config/requires.schema.json");
		if (result == null) {
			throw new ParseException("cannot found requires schema json with: com/massyframework/beanskin/config/requires.schema.json");
		}
		
		return result;
	}
}
